package cc.facesign.acl.service.impl;

import cc.facesign.acl.bean.AclMenu;
import cc.facesign.acl.bean.AclRole;
import cc.facesign.acl.bean.MenuTree;
import cc.facesign.acl.mapper.AclMenuMapper;
import cc.facesign.acl.service.AclMenuService;
import cc.facesign.acl.service.AclRoleService;
import cc.facesign.acl.service.TblUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 权限菜单 服务实现类
 * </p>
 *
 * @author acdongla
 * @since 2022-05-02
 */
@Service
@Transactional
public class AclMenuServiceImpl extends ServiceImpl<AclMenuMapper, AclMenu> implements AclMenuService {

    @Autowired
    private TblUserService userService;

    @Autowired
    private AclRoleService roleService;

    @Autowired
    private AclMenuService menuService;


    @Override
    public List<AclMenu> getByRoleIdBatch(List<String> roleIds) {
        return baseMapper.getByRoleIdBatch(roleIds);
    }

    @Override
    public List<AclMenu> getChildMenuByMenuId(String menuId) {
        MenuTree tree = getMenuTreeByMenuId(menuId);
        List<AclMenu> list = new ArrayList<>();
        getChildMenuByMenuId(tree, list);

        return list;
    }

    @Override
    public List<AclMenu> getListByTree(MenuTree menuTree) {
        Queue<MenuTree> queue = new LinkedList<>();
        queue.add(menuTree);

        List<AclMenu> list = new ArrayList<>();

        while (!queue.isEmpty()) {
            MenuTree poll = queue.poll();
            if (poll.getChildren() != null) queue.addAll(poll.getChildren());
            list.add(poll.getMenu());
        }

        return list;
    }

    private void getChildMenuByMenuId(MenuTree tree, List<AclMenu> list) {
        Queue<MenuTree> queue = new LinkedList<>();
        queue.add(tree);

        while (!queue.isEmpty()) {
            MenuTree poll = queue.poll();
            list.add(poll.getMenu());

            if (poll.getChildren() != null) queue.addAll(poll.getChildren());
        }
    }

    @Override
    public MenuTree getMenuTreeByMenuId(String id) {
        List<AclMenu> all = list(null);
        MenuTree root = new MenuTree();
        root.setMenu(getById(id));

        Map<String, AclMenu> map = new HashMap<>();
        for (AclMenu e : all) {
            map.put(e.getPid(), e);
        }

        getMenuTreeByMenuId(map, root);

        Queue<MenuTree> queue = new LinkedList<>();
        queue.add(root);
        while (!queue.isEmpty()) {
            MenuTree poll = queue.poll();
            BeanUtils.copyProperties(poll.getMenu(), poll);

            if (poll.getChildren() != null) queue.addAll(poll.getChildren());
        }

        return root;
    }

    @Override
    public List<String> getAllPermsByUserId(String id) {

        String rid = userService.getRid(id);

        // 获取所有角色id列表
        List<String> roleIds = roleService.getListByUserId(id).stream()
                .filter(x -> x.getStatus() == 0)
                .filter(x -> x.getRid().equals(rid))
                .map(AclRole::getId)
                .collect(Collectors.toList());

        if (roleIds.size() == 0) return new ArrayList<>();

        // 批量获取menu列表
        List<String> menuIds = menuService.getByRoleIdBatch(roleIds).stream()
                .map(AclMenu::getId)
                .collect(Collectors.toList());

        // 根据menu列表获取perms
        Set<String> set = new HashSet<>();
        for (String menuId : menuIds) {
            Set<String> collect = getChildMenuByMenuId(menuId).stream()
                    .map(AclMenu::getPerms)
                    .collect(Collectors.toSet());
            set.addAll(collect);
        }

        return new ArrayList<>(set);
    }


    private void getMenuTreeByMenuId(Map<String, AclMenu> map, MenuTree u) {
        String pid = u.getMenu().getPid();

        for (Map.Entry<String, AclMenu> e : map.entrySet()) {
            String key = e.getKey();
            AclMenu value = e.getValue();
            if ((pid + ',' + value.getId()).equals(key)) {
                if (u.getChildren() == null) {
                    u.setChildren(new ArrayList<>());
                }

                MenuTree child = new MenuTree();
                child.setMenu(value);
                u.getChildren().add(child);
                getMenuTreeByMenuId(map, child);
            }
        }
    }

}
